package com.xuecheng.checkcode.service.impl;

import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.xuecheng.base.util.EncryptUtil;
import com.xuecheng.checkcode.model.GenerateCheckCodeParamsDTO;
import com.xuecheng.checkcode.model.CheckCodeResultDTO;
import com.xuecheng.checkcode.service.AbstractCheckCodeService;
import com.xuecheng.checkcode.service.CheckCodeService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 * @author Mr.M
 * @version 1.0
 * @description 图片验证码生成器
 * @date 2022/9/29 16:16
 */
@Slf4j
@Service("PicCheckCodeService")
@RequiredArgsConstructor
public class PicCheckCodeServiceImpl extends AbstractCheckCodeService implements CheckCodeService {

    private static final Integer DEFAULT_LENGTH = 4;

    private static final String KEY_PREFIX = "checkcode:";

    private static final Integer DEFAULT_EXPIRE = 300; // 300秒

    private final DefaultKaptcha kaptcha;

    /**
     * 设置验证码生成器
     *
     * @param checkCodeGenerator 验证码生成器
     */
    @Resource(name = "NumberLetterCheckCodeGenerator") // 按照名称注入选用@Resource
    @Override
    public void setCheckCodeGenerator(CheckCodeGenerator checkCodeGenerator) {
        this.checkCodeGenerator = checkCodeGenerator;
    }

    /**
     * 设置key生成器
     *
     * @param keyGenerator key生成器
     */
    @Resource(name = "UUIDKeyGenerator")
    @Override
    public void setKeyGenerator(KeyGenerator keyGenerator) {
        this.keyGenerator = keyGenerator;
    }

    /**
     * 设置验证码存储器
     *
     * @param checkCodeStore 验证码存储器
     */
    @Resource(name = "RedisCheckCodeStore")
    @Override
    public void setCheckCodeStore(CheckCodeStore checkCodeStore) {
        this.checkCodeStore = checkCodeStore;
    }

    /**
     * 生成验证码
     *
     * @param generateCheckCodeParamsDTO 验证码参数
     * @return 验证码结果
     */
    @Override
    public CheckCodeResultDTO generate(GenerateCheckCodeParamsDTO generateCheckCodeParamsDTO) {
        GenerateResult generate = generate(DEFAULT_LENGTH, KEY_PREFIX, DEFAULT_EXPIRE);
        return new CheckCodeResultDTO(generate.getKey(), createPic(generate.getCode()));
    }

    /**
     * 生成图片验证码
     *
     * @param code 验证码
     * @return 图片验证码
     */
    private String createPic(String code) {
        // 生成图片验证码
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        BufferedImage image = kaptcha.createImage(code);
        try {
            // 对字节数组Base64编码
            ImageIO.write(image, "png", outputStream);
            return "data:image/png;base64," + EncryptUtil.encodeBase64(outputStream.toByteArray());
        } catch (IOException e) {
            log.error("生成图片验证码失败：{}", e.getMessage());
            return null;
        } finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                log.error("关闭流失败：{}", e.getMessage());
            }
        }
    }
}
